(provide :rtmlog)

(defclass rtmeus-log
  :super propertied-object
  :slots (rtmstates abstime)
  )

(defmethod rtmeus-log
  (:rtmstates (&rest args) (forward-message-to rtmstates args))
  (:abstime () abstime)
  )

;;read log
(defun read-rtm-log (fname &key num)
  (let ((eof (gensym))
        datum
        (data)
        (ct 0))
    (warn ";; read-rtm-log ")
    (with-open-file
        (f fname :direction :input)
      (while (not (eq eof (setq datum (read f nil eof))))
        (push datum data)
        (when num (>= num ct) (return-from nil))
        (if (zerop (mod (incf ct) 50)) (warn "."))
        )
      )
    (warn " done~%")
    (nreverse data)
    ))

(defun read-rtm-log.gz (fname.gz)
  (let ((eof (gensym))
        datum
        (data)
        (ct 0)
        f)
    (warn ";; read-rtm-log.gz ")
    (setq f (piped-fork "zcat" fname.gz))
    (unwind-protect
         (while (not (eq eof (setq datum (read f nil eof))))
           (push datum data)
           (if (zerop (mod (incf ct) 50)) (warn "."))
           )
      (close f))
    (warn " done~%")
    (nreverse data)
    )
  )

(defun read-rtm-log.bz2 (fname.bz2)
  (let ((eof (gensym))
        datum
        (data)
        (ct 0)
        f)
    (warn ";; read-rtm-log.bz2 ")
    (setq f (piped-fork "bzcat" fname.bz2))
    (unwind-protect
         (while (not (eq eof (setq datum (read f nil eof))))
           (push datum data)
           (if (zerop (mod (incf ct) 50)) (warn "."))
           )
      (close f))
    (warn " done~%")
    (nreverse data)
    )
  )
;;play log
(defun play-logs (logs comp svecs)
  (let ((prevt (send (elt logs 0) :abstime))
        (states nil) lapt sleept)
    (dolist (lg logs)
      (setq lapt (v- (send lg :abstime) prevt))
      (setq sleept (* 1000 (+ (* (elt lapt 0) 1000) (elt lapt 1))))
      (unix:usleep sleept)
      ;;
      (setq prevt (send lg :abstime))
      (dolist (sv svecs)
        (push (list sv :short (send lg :rtmstates sv)) states))
      ;;
      (send comp :set-states states)
      (setq states nil)
      )
    )
  )

(defun play-log (logs comp svec)
  (play-logs logs comp (list svec))
  )

;;visualize log
(defun show-graph (logs vec index &optional (gnufile))
  ""
  (let* ((ct 0))
    (if (null gnufile)
        (setq gnufile (format nil "~A.dat" (string-downcase (string vec)))))
    (if (not (boundp '*gnuplot*)) (setq *gnuplot* (gnuplot)))
    (with-open-file
        (f gnufile :direction :output)
      (dolist (v (send-all logs :rtmstates vec))
        (format f "~A ~A~%" (incf ct) (elt v index)))
      )
    (send *gnuplot* :plot gnufile))
  )

(defun show-graph-with-vel (logs vec index &optional (gnufile))
  ""
  (let* ((ct 0) prev)
    (if (null gnufile)
        (setq gnufile (format nil "~A.dat" (string-downcase (string vec)))))
    (if (not (boundp '*gnuplot*)) (setq *gnuplot* (gnuplot)))
    (with-open-file
        (f gnufile :direction :output)
      (dolist (v (send-all logs :rtmstates vec))
        (when (null prev) (setq prev v))
        (format f "~A ~A ~A~%" (incf ct) (elt v index) 
                (- (elt v index) (elt prev index)))
        (setq prev v))
      )
    (send *gnuplot* :command
          (format nil "plot ~s using 1:2 with lines, ~s using 1:3 with lines" gnufile gnufile))
    )
  )

(defun show-graph-with-function (logs vec index func &optional (gnufile))
  ""
  (let* ((ct 0))
    (if (null gnufile)
        (setq gnufile (format nil "~A.dat" (string-downcase (string vec)))))
    (if (not (boundp '*gnuplot*)) (setq *gnuplot* (gnuplot)))
    (with-open-file
        (f gnufile :direction :output)
      (dolist (v (send-all logs :rtmstates vec))
        (if (listp index)
            (format f "~A ~A~%" (incf ct) (funcall func (mapcar #'(lambda (x) (elt v x)) index)))
            (format f "~A ~A~%" (incf ct) (funcall func (elt v index)))))
      )
    (send *gnuplot* :plot gnufile))
  )

(defun show-graphs (&rest args)
  "show-graphs (list logs vec index) (list logs vec index) ...)"
  (let* ((ct 0) logs vec index vs gnufile gnufiles (file-count 0) 
	 (hoge nil) xrange yrange range)
    (if (not (boundp '*gnuplot*)) (setq *gnuplot* (gnuplot)))
    (while args
      (case (car args)
        (:xrange (pop args) (setq xrange (pop args)))
        (:yrange (pop args) (setq yrange (pop args)))
        (:range  (pop args) (setq  range (pop args)))
        (otherwise
         (push (pop args) hoge))))
    (setq args (nreverse hoge))
    (dolist (argset args)
      (setq gnufile (format nil "/tmp/tmp~A.dat"
                            (incf file-count)))
      (push (list gnufile (format nil "title ~S" (string file-count)))
            gnufiles)
      (setq logs (pop argset))
      (setq vec (pop argset))
      (setq index (pop argset))
      (setq ct 0)
      (with-open-file
          (f gnufile :direction :output)
        (dolist (v (send-all logs :rtmstates vec))	
          (format f "~A ~A~%" (incf ct) (elt v index)))
        ))
    (nreverse gnufiles)
    (if xrange (setq gnufiles (append gnufiles (list :xrange xrange))))
    (if yrange (setq gnufiles (append gnufiles (list :yrange yrange))))
    (if range (setq gnufiles (append gnufiles (list :range range))))
    (if *jsk-debug*
        (warn "(send* *gnuplot* :plot ~S)~%" gnufiles))
    (send* *gnuplot* :plot gnufiles))
  )
